package com.longyou.gateway.security;

import cn.hutool.core.util.StrUtil;
import com.longyou.gateway.util.ServerWebExchangeContextHolder;
import java.util.concurrent.atomic.AtomicReference;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.cloud.constant.CoreConstant;
import org.cloud.core.redis.RedisUtil;
import org.cloud.dimension.userinfo.LoginUserGetParamsDTO;
import org.cloud.entity.LoginUserDetails;
import org.cloud.utils.MD5Encoder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Component
//@Transactional(propagation = Propagation.NEVER)
@Slf4j
@RequiredArgsConstructor(onConstructor_ = @__(@Autowired))
public class SecurityUserDetailsService implements ReactiveUserDetailsService {

    private final UserLoginService userLoginService;

    /**
     * 通过用户名获取登录用户信息
     *
     * @param username 用户名
     * @return
     */
    @Override
    public Mono<UserDetails> findByUsername(final String username) {
        Assert.isTrue(StrUtil.isNotBlank(username), "username can not null!");
        final LoginUserGetParamsDTO loginUserGetParamsDTO = new LoginUserGetParamsDTO();
        AtomicReference<ServerWebExchange> swe = new AtomicReference<>();
        return ServerWebExchangeContextHolder.get().doOnNext(swe::set).then(Mono.defer(() -> {
            ServerHttpRequest request = swe.get().getRequest();
            final String microAppIndex = request.getHeaders().getFirst(CoreConstant._MICRO_APPINDEX_KEY);
            final String userType = request.getHeaders().getFirst(CoreConstant._USER_TYPE_KEY);
            if (userType != null) {
                loginUserGetParamsDTO.getParamMap().put(CoreConstant._USER_TYPE_KEY, userType);
            } else {
                loginUserGetParamsDTO.getParamMap().remove(CoreConstant._USER_TYPE_KEY);
            }
            // 小程序登录后会获取用户名，并进行校验！
            if (swe.get().getRequest().getURI().toString().endsWith("/auth/login")) {
                return userLoginService.userLogin(username, loginUserGetParamsDTO, microAppIndex, swe.get());
            } else {
                loginUserGetParamsDTO.setUserName(username);
                final LoginUserDetails userDetails = getUserByName(swe.get());
                return userDetails == null ? Mono.empty() : Mono.just(userDetails);
            }
        }));
    }

    /**
     * 获取用户
     *
     * @return
     */
    private LoginUserDetails getUserByName(ServerWebExchange swe) {
        if (swe == null) {
            return null;
        }
        final String token = swe.getRequest().getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
        if (StrUtil.isBlank(token)) {
            return null;
        }
        return RedisUtil.single().get(CoreConstant._BASIC64_TOKEN_USER_CACHE_KEY + MD5Encoder.encode(token));
    }
}
